package org.vectrics.recruiter.user.resume.email;

import org.apache.log4j.Logger;
import org.vectrics.common.db.JdbcExecute;
import org.vectrics.hibernate.ThreadProperties;
import org.vectrics.user.FindCommonFirstNamesTarget;
import org.vectrics.user.FindCommonLastNamesTarget;
import org.vectrics.user.PersonName;
import org.vectrics.user.PersonNameList;

public class NameExtractor {
	
	private transient Logger log = Logger.getLogger(this.getClass());
	public NameExtractor() {
		super();
	}

	private boolean isCapitalized(char c) {
		return(((c >= 'A') && (c <= 'Z')));
	}
	
	private boolean isWordAllAlphas(String string) {
		char[] charArray = string.toCharArray();
		boolean result = true;
		int i = 0;
		while (i < charArray.length - 1) {
			char c = charArray[i];
			if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))) {
				result = true;
			} else {
				result = false;
			}
			i++;
		}
		return(result);
	}
	
	
	public PersonNameList findNamesInText(WordList wordList) {
		PersonNameList names = new PersonNameList();
		
		findNamesWithNoInitials(wordList, names);
		findNamesWithMiddleInitial(wordList, names);
		findNamesWithFirstInitialAndMiddleName(wordList, names);
		findNamesWithFirstAndMiddleInitial(wordList, names);
		
		return(names);
	}

	private void findNamesWithNoInitials(WordList wordList, PersonNameList names) {
		log.debug("Find two or three consecutive words that are capatalized");
		for (int i = 0; i < wordList.size() - 1; i++) {
			Word word1 = wordList.findWord(i); 
			Word space1 = wordList.findWord(i + 1); 
			Word word2 = wordList.findWord(i + 2); 
			Word space2 = wordList.findWord(i + 3); 
			Word word3 = wordList.findWord(i + 4);
	
			if (
					(space1 != null)
					&& (space2 != null)
					&& (space1.getType().equals(Word.TYPE_WHITESPACE))
					&& (space2.getType().equals(Word.TYPE_WHITESPACE))) { 
				// Three capitalized words in a row, assume first, middle, last
				if ((word1 != null) && (word2 != null) && (word3 != null)
						&& (this.isWordProperFormat(word1))
						&& (this.isWordProperFormat(word2))
						&& (this.isWordProperFormat(word3))
						&& ((this.isWordAPossibleFirstName(word1)) 
								|| (this.isWordAPossibleFirstName(word2)) || (this.isWordAPossibleLastName(word3)))
						&& (word1.getValue().length() > 1)
						&& (word2.getValue().length() > 1)
						&& (word3.getValue().length() > 1)
						) {
					PersonName name = new PersonName();
					name.setFirstName(word1.getValue());
					name.setMiddleName(word2.getValue());
					name.setLastName(word3.getValue());
					names.add(name);
					
				}
			}
			
			log.debug("Two capitalized words in a row, assume first, last");
			if ((space1 != null)
					&& (space1.getType().equals(Word.TYPE_WHITESPACE))) {
				if ((word1 != null) && (word2 != null)
						&& (this.isWordProperFormat(word1))
						&& (this.isWordProperFormat(word2))
						&& ((this.isWordAPossibleFirstName(word1)) || (this.isWordAPossibleLastName(word2)))
						&& (word1.getValue().length() > 1)
						&& (word2.getValue().length() > 1)
						) {
					PersonName name = new PersonName();
					name.setFirstName(word1.getValue());
					name.setMiddleName(null);
					name.setLastName(word2.getValue());
					names.add(name);
				}
			}
		}
	}

	private void findNamesWithMiddleInitial(WordList wordList, PersonNameList names) {
		for (int i = 0; i < wordList.size() - 1; i++) {
			Word word1 = wordList.findWord(i); 
			Word space1 = wordList.findWord(i + 1); 
			Word word2 = wordList.findWord(i + 2); 
			Word period1 = wordList.findWord(i + 3); 
			Word space2 = wordList.findWord(i + 4); 
			Word word3 = wordList.findWord(i + 5);
	
			if (
					(space1 != null)
					&& (space2 != null)
					&& (space1.getType().equals(Word.TYPE_WHITESPACE))
					&& (space2.getType().equals(Word.TYPE_WHITESPACE))
					&& (period1 != null)
					&& (period1.getType().equals(Word.TYPE_PUNCTUATION))
					&& (period1.getValue().equals("."))
					) { 
				// Three capitalized words in a row, assume first, middle, last
				if ((word1 != null) && (word2 != null) && (word3 != null)
						&& (this.isWordProperFormat(word1))
						&& (this.isWordProperFormat(word2))
						&& (this.isWordProperFormat(word3))
						&& ((this.isWordAPossibleFirstName(word1)) || (this.isWordAPossibleLastName(word3)))
						&& (word1.getValue().length() > 1)
						&& (word2.getValue().length() == 1)
						&& (word3.getValue().length() > 1)
						) {
					PersonName name = new PersonName();
					name.setFirstName(word1.getValue());
					name.setMiddleName(word2.getValue() + ".");
					name.setLastName(word3.getValue());
					names.add(name);
				}
			}
		}
	}
	
	private void findNamesWithFirstAndMiddleInitial(WordList wordList, PersonNameList names) {
		// Find two or three consecutive words that are capatalized
		for (int i = 0; i < wordList.size() - 1; i++) {
			Word word1 = wordList.findWord(i); 
			Word period1 = wordList.findWord(i + 1); 
			Word space1 = wordList.findWord(i + 2); 
			Word word2 = wordList.findWord(i + 3); 
			Word period2 = wordList.findWord(i + 4); 
			Word space2 = wordList.findWord(i + 5); 
			Word word3 = wordList.findWord(i + 6);
	
			if (
					(space1 != null)
					&& (space2 != null)
					&& (space1.getType().equals(Word.TYPE_WHITESPACE))
					&& (space2.getType().equals(Word.TYPE_WHITESPACE))
					&& (period1 != null)
					&& (period1.getType().equals(Word.TYPE_PUNCTUATION))
					&& (period1.getValue().equals("."))
					&& (period2 != null)
					&& (period2.getType().equals(Word.TYPE_PUNCTUATION))
					&& (period2.getValue().equals("."))
					) { 
				
				// Three capitalized words in a row, assume first, middle, last
				if ((word1 != null) && (word2 != null) && (word3 != null)
						&& (this.isWordProperFormat(word1))
						&& (this.isWordProperFormat(word2))
						&& (this.isWordProperFormat(word3))
						&& (this.isWordAPossibleLastName(word3))
						&& (word1.getValue().length() == 1)
						&& (word2.getValue().length() == 1)
						&& (word3.getValue().length() > 1)
						) {
					PersonName name = new PersonName();
					name.setFirstName(word1.getValue() + ".");
					name.setMiddleName(word2.getValue() + ".");
					name.setLastName(word3.getValue());
					names.add(name);
				}
			}
		}
	}
	
	private void findNamesWithFirstInitialAndMiddleName(WordList wordList, PersonNameList names) {
		// Find two or three consecutive words that are capatalized
		for (int i = 0; i < wordList.size() - 1; i++) {
			Word word1 = wordList.findWord(i); 
			Word period1 = wordList.findWord(i + 1); 
			Word space1 = wordList.findWord(i + 2); 
			Word word2 = wordList.findWord(i + 3); 
			Word space2 = wordList.findWord(i + 4); 
			Word word3 = wordList.findWord(i + 5);
	
			if (
					(space1 != null)
					&& (space2 != null)
					&& (space1.getType().equals(Word.TYPE_WHITESPACE))
					&& (space2.getType().equals(Word.TYPE_WHITESPACE))
					&& (period1 != null)
					&& (period1.getType().equals(Word.TYPE_PUNCTUATION))
					&& (period1.getValue().equals("."))
					) { 
				// Three capitalized words in a row, assume first, middle, last
				if ((word1 != null) && (word2 != null) && (word3 != null)
						&& (this.isWordProperFormat(word1))
						&& ((this.isWordAPossibleFirstName(word2)) || (this.isWordAPossibleLastName(word3)))
						&& (this.isWordProperFormat(word3))
						&& (word1.getValue().length() == 1)
						&& (word2.getValue().length() > 1)
						&& (word3.getValue().length() > 1)
						) {
					PersonName name = new PersonName();
					name.setFirstName(word1.getValue() + ".");
					name.setMiddleName(word2.getValue());
					name.setLastName(word3.getValue());
					names.add(name);
				}
			}
		}
	}
	
	private boolean isWordAPossibleFirstName(Word word) {
		boolean result = isWordProperFormat(word);
		if (word.getValue().length() > 1) {
			if (result) {
				FindCommonFirstNamesTarget target = new FindCommonFirstNamesTarget(word.getValue(), false);
				JdbcExecute.execute(ThreadProperties.getSession(), target);
				if (target.getMatches().size() > 0)
					result = true;
				else
					result = false;
			}
		}
		return(result);
	}
	
	
	private boolean isWordAPossibleLastName(Word word) {
		boolean result = isWordProperFormat(word);
		if (result) {
			FindCommonLastNamesTarget target = new FindCommonLastNamesTarget(word.getValue(), false);
			JdbcExecute.execute(ThreadProperties.getSession(), target);
			if (target.getMatches().size() > 0)
				result = true;
			else
				result = false;
		}
		return(result);
	}
	
	private boolean isWordProperFormat(Word word) {
		boolean result = false;
		if (word.getType() == Word.TYPE_WORD) {
			if (isWordAllAlphas(word.getValue())) {
				if (isCapitalized(word.getValue().charAt(0))) {
					result = true;
				}
			}
		}
		return(result);
	}
	
}
